10. Dynamic Proxy

Dynamic Proxy

In this lesson, you'll learn the basics of using dynamic proxies in Java.

ND079 JPND C2 L04 A09 Dynamic Proxy

What is a Dynamic Proxy?

A dynamic proxy is a class that implements a list of interfaces specified at runtime.

When you write a class to implement an interface statically, you need to know at compile-time what interfaces you're going to implement.

By contrast, if you use a dynamic proxy, you don't need to know at compile-time what interfaces will be implemented. This is all determined at runtime. This is what makes dynamic proxies "dynamic".

How Do Dynamic Proxies Work?

  1. First, you create a custom InvocationHandler. InvocationHandler is an abstract class that receives method invocations. A method invocation is a Method and an array of parameters.

  2. Then, you create a dynamic proxy instance using the Proxy.newProxyInstance()).

  3. When clients call a method on the proxy instance, the method invocation is forwared to your MethodInvocationHandler.

What are some good uses of dynamic proxies?

SOLUTION:
  • Creating method interceptors, such as for Aspect Oriented Programming.
  • Creating a general Decorator wrapper so that you do not need to now the interface being wrapped at compile-time.

Dynamic Proxy Demo

ND079 JPND C2 L04 A10 Demo Dynamic Proxy

Code from the Demo

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashSet;
import java.util.Set;

public final class LoggingProxy {
    public static void main(String[] args) {

        Set<String> targetSet = new HashSet<>();

        Object proxy = Proxy.newProxyInstance(
                LoggingProxy.class.getClassLoader(),
                new Class[]{Set.class},
                new LoggingInvocationHandler(targetSet));

        Set<String> loggedSet = (Set<String>) proxy;
        loggedSet.add("item");

        System.out.println(targetSet.contains("item"));
    }

    static class LoggingInvocationHandler implements InvocationHandler {

        private final Object targetObject;

        public LoggingInvocationHandler(Object targetObject) {
            this.targetObject = targetObject;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println(targetObject.getClass() + "." + method.getName() + "()");
            return method.invoke(targetObject, args);
        }
    }
}

Further Reading